
using System;
using System.Collections.Generic;

//using Cairo;
//using Gtk;

using stefc.geo.lib;
using stefc.geo.platform;

namespace MyLocate
{

	public class Drawing
	{
		private const Int32 BACKGROUND_COLOR = 0x00495A51;
		private const Int32 LINE_COLOR = 0x0094CCB1;
		
		
		private string[] METRIC_UNITS = new string[] 
		{"1 m","10 m","100 m","1 km","10 km","100 km","1000 km"};
		
		private string[] US_UNITS = new string[]
		{"1 yd","10 yd","100 yd","1 mi","10 mi","100 mi","1000 mi"};
		
		private string[] DIRECTIONS = new string[]
		{"N","NE","E","SE","S", "SW","W","NW"};
		
		private const int SECTORS = 8;
		private const double MAX_RANGE = 25000 * 1000; // 40.000km 
		
		private readonly string caption;
		private readonly int radius;
		private readonly bool metric;
		private readonly double angleOffset;
		
		private readonly ICanvas canvas;
		
		public Drawing (ICanvas canvas, string caption, 
		                int width, int height, 
		                bool metric, double angleOffset)
		{
			this.canvas=canvas;
			this.caption=caption;
			this.radius=((width < height ? width:height) / 2)-4;
			this.metric=metric;
			this.angleOffset=angleOffset;
				
			// font auswählen
			canvas.SelectFont("Georgia", false,false);
			
			// schwarzer hintergrund
			this.canvas.FillRect(-width/2,-height/2,width,height,
			                     ColorMapFactory.Black);
		}
		
		public void Paint()
		{       
	        // Background zeichnen
			canvas.Circle(radius, 5, ColorMapFactory.White, BACKGROUND_COLOR);
						
			// Kreis in Sektoren aufteilen
			foreach(double angle in MathUtil.IterateAngle(SECTORS))
			{
				Cartesian start = this.GetPosition(angle,this.GetDistance(2));
				Cartesian end = this.GetPosition(angle,this.GetDistance(6));
				canvas.Line(start, end, 1, LINE_COLOR);
			}
			
			// Zentrum beschriften
			this.TextOut(Cartesian.Zero,this.caption,11.0d);
			
			// Himmelsrichtungen anzeigen
			this.DrawLabels();
			
			// einzelne Distanzringe und Beschriftung zeichnen
			for(int n=2; n<=6; n++)
			{
				double meter = this.GetDistance(n);
				double factor= this.GetFactor(meter);
				canvas.Circle(factor*radius,1,LINE_COLOR);
				
				double angle =
					(Math.PI/4) *(
					              (n % 2) == 0 ? 5 : 3 );
				
				Cartesian point=this.GetPosition(angle,meter);
				this.TextOut(point,
				    this.GetUnitLabel(n), 8.0d);
			}
		}
		
		private Cartesian GetPosition(double angle, double distance)
		{
			double factor= this.GetFactor(distance);	
			return new Cartesian(
				Math.Cos(angle+this.angleOffset-(Math.PI/2))*radius*factor,
			    Math.Sin(angle+this.angleOffset-(Math.PI/2))*radius*factor);
		}
		
		private void TextOut(Cartesian coord, string text, double fontSize)
		{
			double pt = this.radius * 0.006 * fontSize;			
			canvas.TextOut(coord,text,pt,
				ColorMapFactory.White,
			    ColorMapFactory.Black, 
			    BACKGROUND_COLOR);
		}
		
		private void DrawLabels()
		{
			double sector= Math.PI/4;
			for(int i=0;i<SECTORS;i++)
			{
				Cartesian point = this.GetPosition(sector*i, 8000000);
				this.TextOut(point,
					DIRECTIONS[i], i % 2 == 0 ? 16.0d: 10.0d );
			}
		}
		
		private double GetDistance(int n)
		{
			if(this.metric)
				return Math.Pow(10,n);
			else if(n <= 2) 
				return MathUtil.YardToMeter(Math.Pow(10,n));
			else 
				return MathUtil.MileToMeter(Math.Pow(10,n-3));
		}
		
		private string GetUnitLabel(int n)
		{
			return this.metric ? METRIC_UNITS[n] : US_UNITS[n];
		}
		
		// wir haben eine logarithmische Skala von 0 bis 40.000km 
		public static double GetFactor(double meter)
		{
			return Math.Log10(meter)/Math.Log10(MAX_RANGE);
		}
		
		public void DrawPin(double angle, double distance, Int32 color)
		{
			Cartesian point = this.GetPosition(angle,distance);
			canvas.Pin(point, this.radius * 0.04, color);
		}
		
	}
}